class IndexdbHelper {
  haveIndex = false;
  canuseIndex = false;
  tbConfigs = [];

  constructor(databaseName, tbConfigs, dbVersion) {
    this.databaseName = databaseName;
    this.dbVersion = dbVersion || 2;
    this.tbConfigs = tbConfigs || [];

    if (window.indexedDB) {
      this.haveIndex = true;
    } else this.haveIndex = false;
  } // indexdb 初始化


  ready() {
    if (this.haveIndex) {
      if (this.db) return Promise.resolve(this.db);
      return new Promise(async (resolve, reject) => {
        const request = window.indexedDB.open(this.databaseName, this.dbVersion);

        request.onerror = () => {
          console.log("数据库打开报错");
          this.canuseIndex = false;
          reject();
        };

        request.onsuccess = async () => {
          this.db = request.result;
          console.log("数据库打开成功");
          this.canuseIndex = true;
          resolve(this.db);
        };

        request.onupgradeneeded = event => {
          this.canuseIndex = true;
          this.db = event.target.result;
          this.initTb();
          const transaction = event.target.transaction;

          transaction.oncomplete = function () {
            resolve(this.db);
          };
        };
      });
    }

    return Promise.resolve(null);
  } // 创建表


  createStore(tbName, tconfig) {
    if (!this.canuseIndex || !this.haveIndex) return;
    let objectStore;

    if (!this.db?.objectStoreNames.contains(tbName)) {
      const {
        keyPath,
        indexs = [],
        ...config
      } = tconfig || {};
      let key = keyPath;
      let indexList = indexs;

      if (!key) {
        key = "id";
        config.autoIncrement = true;

        if (!indexList.length) {
          indexList = [{
            name: "id",
            prop: "id",
            config: {
              unique: true
            }
          }];
        }
      }

      objectStore = this.db?.createObjectStore(tbName, { ...config,
        keyPath: key
      });
      indexList.forEach(index => this.createIndex(objectStore, index));
    }

    return objectStore;
  } // 创建index


  createIndex(tb, index) {
    if (!tb || !this.db) return false;
    let sotre;

    if (typeof tb === "string") {
      sotre = this.db.transaction(tb).objectStore(tb);
    } else {
      sotre = tb;
    }

    const {
      name,
      prop,
      config
    } = index;
    sotre.createIndex(name, prop, config);
    return true;
  } // 删除表中所有数据


  dropStore(tbName) {
    return new Promise((resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      const objectStore = this.db.transaction(tbName).objectStore(tbName);
      const request = objectStore.openCursor();

      request.onsuccess = function (event) {
        const cursor = event.target.result;

        if (cursor) {
          cursor.delete();
        } else {
          resolve(true);
        }
      };

      request.onerror = function () {
        reject();
      };
    });
  } // 插入数据


  create(tbName, data) {
    return new Promise(async (resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      const keyPath = this.db.transaction([tbName], "readwrite").objectStore(tbName).keyPath;
      const isExist = await this.findByPk(tbName, data[keyPath]);
      if (isExist) resolve(true);
      const request = this.db.transaction([tbName], "readwrite").objectStore(tbName).add(data);

      request.onsuccess = function () {
        resolve(data);
      };

      request.onerror = function () {
        reject();
      };
    });
  }

  bulkCreate(tbName, data) {
    return new Promise(async (resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      if (!Array.isArray(data) || data.length === 0) return resolve(true);
      const retList = await Promise.all(data.map(async d => await this.create(tbName, d)));
      if (retList.every(t => !!t)) resolve(true);else reject();
    });
  } // 根据主键查找


  findByPk(tbName, keyPath) {
    return new Promise((resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      const transaction = this.db.transaction([tbName]);
      const objectStore = transaction.objectStore(tbName);
      const request = objectStore.get(keyPath);

      request.onerror = function () {
        reject();
      };

      request.onsuccess = function () {
        if (request.result) {
          resolve(request.result);
        } else {
          resolve(null);
        }
      };
    });
  } // 根据索引查找


  findByIndex(tbName, indexName, keyPath) {
    return new Promise((resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      const request = this.db.transaction([tbName]).objectStore(tbName).index(indexName).get(keyPath);

      request.onerror = function () {
        reject();
      };

      request.onsuccess = function (e) {
        const result = e.target.result;

        if (result) {
          resolve(result);
        } else {
          resolve(null);
        }
      };
    });
  } //   遍历指定表


  query(tbName, filter) {
    return new Promise((resolve, reject) => {
      const list = [];
      if (!this.canuseIndex || !this.db) return reject();
      const objectStore = this.db.transaction(tbName).objectStore(tbName);
      const request = objectStore.openCursor();

      request.onsuccess = function (event) {
        const cursor = event.target.result;

        if (cursor) {
          if (!filter || filter(cursor.value)) list.push(cursor.value);
          cursor.continue();
        } else {
          resolve(list);
        }
      };

      request.onerror = function () {
        reject();
      };
    });
  } //   遍历指定表


  forEach(tbName, callback) {
    return new Promise((resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      const objectStore = this.db.transaction(tbName).objectStore(tbName);
      const request = objectStore.openCursor();

      request.onsuccess = function (event) {
        const cursor = event.target.result;

        if (cursor) {
          callback(cursor);
        } else {
          resolve(true);
        }
      };

      request.onerror = function () {
        reject();
      };
    });
  } //   更新指定数据


  update(tbName, data) {
    return new Promise((resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      const request = this.db.transaction([tbName], "readwrite").objectStore(tbName).put(data);

      request.onsuccess = function () {
        resolve(data);
      };

      request.onerror = function () {
        reject();
      };
    });
  } // 删除数据


  delete(tbName, keyPath) {
    return new Promise((resolve, reject) => {
      if (!this.canuseIndex || !this.db) return reject();
      const request = this.db.transaction([tbName], "readwrite").objectStore(tbName).delete(keyPath);

      request.onsuccess = function () {
        resolve(true);
      };

      request.onerror = function (e) {
        reject(e);
      };
    });
  }

  initTb() {
    this.tbConfigs.forEach(({
      name,
      ...config
    }) => {
      this.createStore(name, config);
    });
  }

}

export default IndexdbHelper;